#include "mymodbus.h"
#include <string.h>
#include "my485.h"
#include "mypwm.h"

modbus_TypeDef Modbus;    //定义结构体

/* 寄存器数据 */
uint16_t Reg[] = {0x0001,
                  0x0003,
                  0x0000,
                  0x0001,
                  0x0001,
                  0x0001,
                  0x0001,
                  0X0001
                 };

/* modbus初始化*/
void Modbus_Init(void)
{
    Modbus.address = 0x01;          /* 基地址位01 */
		Modbus.MessageFlag = 0;
}

uint16_t Modbus_processing(void)
{
  uint16_t crc,rccrc;                                                             //定义两个获取接收和计算校验码的变量	

	crc = HAL_CRC_Calculate(&hcrc, (uint32_t *)Modbus.ModBus_recvBuff, 6);
	rccrc = (Modbus.ModBus_recvBuff[7]<<8) + Modbus.ModBus_recvBuff[6];
	if(crc == rccrc)
	{
		if(Modbus.ModBus_recvBuff[0] == Modbus.address){
			switch(Modbus.ModBus_recvBuff[1])
			{
				case 3:      Function_03(crc);  break;
        case 6:      Function_06(crc);  break;
				default: return 3;
			}
		}
		else{
			return 2;
		}
	}
	else
	{
		return 1;
	}
	
	return 0;
}

uint16_t Function_03(uint16_t crcInput)
{
	uint8_t i = 0,j = 0;
	uint16_t CRCOutput = 0;
	
	uint16_t address = (((uint16_t)Modbus.ModBus_recvBuff[2]<<8) | Modbus.ModBus_recvBuff[3]);
	uint16_t number = (((uint16_t)Modbus.ModBus_recvBuff[4]<<8) | Modbus.ModBus_recvBuff[5]);//寄存器数量
	
	Modbus.ModBus_sendBuff[i++] = Modbus.address;
	Modbus.ModBus_sendBuff[i++] = 0x03;
	Modbus.ModBus_sendBuff[i++] = (2 * number)&0xFF;					//返回字节数=2*寄存器数量
	
	for(j=0; j<number; j++)
	{
		Modbus.ModBus_sendBuff[i++] = Modbus.ModBus_ReadReg[address+j]>>8;
		Modbus.ModBus_sendBuff[i++] = Modbus.ModBus_ReadReg[address+j]&0xFF;
	}
	
	CRCOutput = HAL_CRC_Calculate(&hcrc, (uint32_t *)Modbus.ModBus_sendBuff, i);
//	debugnum = CRCOutput;
	Modbus.ModBus_sendBuff[i++] = CRCOutput & 0xFF;
	Modbus.ModBus_sendBuff[i++] = CRCOutput>>8;
	
	RS485_SendsomeByte((uint8_t*)Modbus.ModBus_sendBuff, i);
	
	return 0;
}

uint16_t Function_06(uint16_t crcInput)
{
	uint8_t i = 0;
	uint16_t address = (((uint16_t)Modbus.ModBus_recvBuff[2]<<8) | Modbus.ModBus_recvBuff[3]);
	uint16_t Data = (((uint16_t)Modbus.ModBus_recvBuff[4]<<8) | Modbus.ModBus_recvBuff[5]);
	switch(address)
	{
		case 0x60:	//控制方式
		{
			if(Data == 0x0000)				//上位机
			{
				Motor_Vars.motorStopFlAG = 1;
				Motor_Vars.ControlMode = 0;
				Motor_Vars.Motor_AimSpeed = 0;
			}
			else if(Data == 0x0001)	//按钮
			{
				Motor_Vars.motorStopFlAG = 1;
				Motor_Vars.ControlMode = 1;
				Motor_Vars.Motor_AimSpeed = 0;
				Motor_Vars.motorStartFlAG = 1;
			}
			else if(Data == 0x0002)	//脚踏
			{
				Motor_Vars.motorStopFlAG = 1;
				Motor_Vars.ControlMode = 2;
				Motor_Vars.Motor_AimSpeed = 0;
				Motor_Vars.motorStartFlAG = 1;
			}
			else
				return 2;
			break;		
		}
		case 0x70:	//启停
		{
			if(Motor_Vars.ControlMode == 0)
			{
				if(Data == 0x0000)				//启动
				{
					Motor_Vars.motorStartFlAG = 1;
				}
				else if(Data == 0x0001)		//停止
				{
					Motor_Vars.motorStopFlAG = 1;
				}
				else
					return 2;
				break;
			}
			else
				return 4;

		}						
		case 0x80:	//正反转
		{
			if(Motor_Vars.motorStateFLAG == MOTOR_IDLE)
			{
				if(Data == 0x0005)				//CW
				{
					Motor_Vars.Motor_DIR = 0;
				}
				else if(Data == 0x000A)		//CCW
				{
					Motor_Vars.Motor_DIR = 1;
				}
				else
				return 2;
			}
			else
				return 3;
			break;
		}	
		case 0x90:	//速度
		{
			modbusdebug++;
			if(Data > 8000)
			{
				Data = 8000;
			}
			Motor_Vars.Motor_AimSpeed = (uint32_t)Data * 10;
			break;
		}
		case 0x0A:	//PVDD电源
		{
			if(Data == 0x0000)	//断电
			{
				HAL_GPIO_WritePin(BREAK_PVDD_GPIO_Port,BREAK_PVDD_Pin,GPIO_PIN_RESET);
			}
			else if(Data == 0x0001)	//通电
			{
				HAL_GPIO_WritePin(BREAK_PVDD_GPIO_Port,BREAK_PVDD_Pin,GPIO_PIN_SET);
			}
			else
				return 2;
			break;
		}
		case 0x0B:	//紧急制动
		{
			if(Data == 0x0001)
			{
				Brake_Stop_Motor();
			}
			break;
		}
		case 0xF0:
		{
			if(Data == 0x0000)			//停止
			{
				
			}
			else if(Data == 0x0001)	//启动
			{
				
			}
			break;
		}
		
		default:		//Error
		return 1;
				
	}
	Modbus.ModBus_sendBuff[i++] = Modbus.address;
	Modbus.ModBus_sendBuff[i++] = 0x06;
	Modbus.ModBus_sendBuff[i++] = address>>8;
	Modbus.ModBus_sendBuff[i++] = address & 0xFF;
	Modbus.ModBus_sendBuff[i++] = Data>>8;
	Modbus.ModBus_sendBuff[i++] = Data & 0xFF;
	Modbus.ModBus_sendBuff[i++] = crcInput & 0xFF;
	Modbus.ModBus_sendBuff[i++] = crcInput>>8;
	RS485_SendsomeByte((uint8_t*)Modbus.ModBus_sendBuff, i);
	
	
	
	return 0;
}


#if 0
/* 功能03:主机读取从机 */
void Function_03(void)
{
    uint16_t Regadd, Reglen,crc;
    uint8_t i,j;
    i = 0;
    Regadd = (Modbus.receive[2]<<8)+Modbus.receive[3];//要读取寄存器的首地址
    Reglen = (Modbus.receive[4]<<8)+Modbus.receive[5];//要读取寄存器个数
    //开始打包数据包
    Modbus.send[i++] = Modbus.address;                //ID号
    Modbus.send[i++] = 0x03;                          //功能码
    Modbus.send[i++] = ((Reglen*2)%256);              //返回字节个数
    for(j=0;j<Reglen;j++)
    {
        Modbus.send[i++] = Reg[Regadd+j]>>8;          //寄存器数据的高位；因为寄存器是16位，所以要分成2个8位发送
        Modbus.send[i++] = Reg[Regadd+j]%256;         //寄存器数据的地位
    }
    crc = Modbus_CRC16(Modbus.send,i);                //计算校验码；同理校验码是16位
    Modbus.send[i++] = crc>>8;                        //返回校验码高位
    Modbus.send[i++] = crc%256;                       //返回校验码地位
    //打包好数据开始发送
    HAL_UART_Transmit_DMA (&huart1,(uint8_t*)Modbus.send,i);       // 发送方式DMA

}

/* 功能06:主机写入从机 */
void Function_06(void)
{
    uint16_t Regadd,crc,val;                          //地址；验证码；要修改的值；
    uint16_t i;
    i = 0;
    Regadd = (Modbus.receive[2]<<8)+Modbus.receive[3];      //获取要修改的地址
    val = (Modbus.receive[4]<<8)+Modbus.receive[5];         //获取修改的数值
    Reg[Regadd] = val;                                //修改数值
    //开始打包回应包
    Modbus.send[i++] = Modbus.address;                //从机地址
    Modbus.send[i++] = 0x06;                          //功能码
    Modbus.send[i++] = Regadd>>8;                     //返回写入地址
    Modbus.send[i++] = Regadd%256;
    Modbus.send[i++] = val>>8;                        //返回写入数值
    Modbus.send[i++] = val%256;
    crc = Modbus_CRC16(Modbus.send,i);                //校验码
    Modbus.send[i++] = crc>>8;                        //返回校验码高位
    Modbus.send[i++] = crc%256;                       //返回校验码地位
    //数据打包完开始发回
    HAL_UART_Transmit_DMA (&huart1,(uint8_t*)Modbus.send,i);       // 发送方式DMA
}
#endif
